package net

import (
	"duanju-mq/pkg/config"
	"duanju-mq/pkg/util/rand"
	"errors"
	"net"
	"strconv"
)

var fLocalIP = config.String("host.ip.local", getLocalIP(), "intranet ip")

func getLocalIP() string {
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return ""
	}
	for _, addr := range addrs {
		ip, _, _ := net.ParseCIDR(addr.String())
		if s := ip.String(); isLocalIP(s) {
			return s
		}
	}
	return ""
}

/*
Address Block                    Name                              RFC
0.0.0.0/8                        "This host on this network"       [RFC1122], section 3.2.1.3
10.0.0.0/8                       Private-Use                       [RFC1918]
100.64.0.0/10                    Shared Address Space              [RFC6598]
127.0.0.0/8                      Loopback                          [RFC1122], section 3.2.1.3
169.254.0.0/16                   Link Local                        [RFC3927]
172.16.0.0/12                    Private-Use                       [RFC1918]
192.0.0.0/24[2]                  IETF Protocol Assignments         [RFC6890], section 2.1
192.0.0.0/29                     IPv4 Service Continuity Prefix    [RFC7335]
192.0.0.8/32                     IPv4 dummy address                [RFC7600]
192.0.0.9/32                     Port Control Protocol Anycast     [RFC-ietf-pcp-anycast-08]
192.0.0.170/32, 192.0.0.171/32   NAT64/DNS64 Discovery             [RFC7050], section 2.2
192.0.2.0/24                     Documentation (TEST-NET-1)        [RFC5737]
192.31.196.0/24                  AS112-v4                          [RFC7535]
192.52.193.0/24                  AMT                               [RFC7450]
192.88.99.0/24                   Deprecated (6to4 Relay Anycast)   [RFC7526]
192.168.0.0/16                   Private-Use                       [RFC1918]
192.175.48.0/24                  Direct Delegation AS112 Service   [RFC7534]
198.18.0.0/15                    Benchmarking                      [RFC2544]
198.51.100.0/24                  Documentation (TEST-NET-2)        [RFC5737]
203.0.113.0/24                   Documentation (TEST-NET-3)        [RFC5737]
240.0.0.0/4                      Reserved                          [RFC1112], section 4
255.255.255.255/32               Limited Broadcast                 [RFC919], section 7
*/

var isLocalIP = func() func(ip string) bool {
	list := []*net.IPNet{
		cidr("10.0.0.0/8"),
		cidr("172.16.0.0/12"),
		cidr("192.168.0.0/16"),
		cidr("100.64.0.0/10"),
	}
	return func(ip string) bool {
		i := net.ParseIP(ip)
		if i == nil {
			return false
		}
		for _, a := range list {
			if a.Contains(i) {
				return true
			}
		}
		return false
	}
}()

func cidr(s string) *net.IPNet {
	_, i, _ := net.ParseCIDR(s)
	return i
}

func IsLocalIP(ip string) bool {
	return isLocalIP(ip)
}

func LocalIP() string {
	return *fLocalIP
}

func GetValidListener(ip string, from, to int) (net.Listener, int, error) {
	if from > to {
		from, to = to, from
	}
	r := rand.In(from, to)
	for p := r; p <= to; p++ {
		l, e := net.Listen("tcp", ip+":"+strconv.Itoa(p))
		if e == nil {
			return l, p, nil
		}
	}
	for p := r - 1; p >= from; p-- {
		l, e := net.Listen("tcp", ip+":"+strconv.Itoa(p))
		if e == nil {
			return l, p, nil
		}
	}
	return nil, 0, errors.New("No valid port")
}
